package main

import (
	"fmt"
	"log"
	"reflect"
	"runtime/debug"
	"strconv"
	"time"
)

var templeTime string = "2006-01-02 15:04:05"

type QuartzGo struct {
	//last     int //延迟时间
	tim      string //运行时间
	function interface{}
	args     []interface{}
	sign     int       //0为延迟运行，1为定时运行一次，2为每日定时运行
	oldTime  time.Time //上次运行时间
	end      bool
}

//初始化
func (this QuartzGo) Init(sign int, tim string, function interface{}, args []interface{}) {
	this.sign = sign
	this.tim = tim
	this.function = function
	this.args = args
	this.end = false
	defer func() {
		if err := recover(); err != nil {
			log.Printf("work failed:%s", err)
			debug.PrintStack()
		}
	}()
	switch sign {
	case 0:
		{
			fmt.Println("作为延迟运算")
			this.init_0()
		}
	case 1:
		{
			this.init_1()
		}
	case 2:
		{
			this.init_2()
		}
	default:
		{
			panic("初始化标识位不正确，请填入0，1，2中一种")
		}
	}
	//for ;this.end==false ;  {
	//	_=0
	//}
}

//定时运行一次初始化
func (this QuartzGo) init_1() {
	fmt.Println("延迟运行方法begin")
	//var cc=make(chan int,1)
	//defer close(cc)
	tim, err := Str2Time(this.tim)
	if err != nil {
		panic(err)
	}
	go runProc1(tim, this.function, this.args)
	//_=<-cc
	this.end = true
	fmt.Println("延迟运行方法结束")
}
func runProc1(tim time.Time, function interface{}, args []interface{}) {
	fmt.Println("开始延迟运算")
	for true {
		nowTime := time.Now()
		if tim.Before(nowTime) {
			break
		}
	}
	fun := reflect.ValueOf(function)
	var listVal []reflect.Value
	for _, v := range args {
		listVal = append(listVal, reflect.ValueOf(v))
	}
	fun.Call(listVal)
	fmt.Println("运行方法结束")
	//cc<-1
}

//字符串转时间
func Str2Time(timStr string) (tim time.Time, err error) {
	//TODO判定字符串格式
	tim, err = time.ParseInLocation(templeTime, timStr, time.Local)
	return
}

//延迟运行初始化(tim为秒级单位)
func (this QuartzGo) init_0() {
	//var cc=make(chan int,1)
	//defer close(cc)
	count, err := strconv.Atoi(this.tim)
	if err != nil {
		panic(err)
	}
	fmt.Println(count)
	go runProc(count*1000000000, this.function, this.args)
	//time.Sleep(3000000000)
	//_=<-cc
	this.end = true
	fmt.Println("延迟运行方法结束")
}

func runProc(count int, function interface{}, args []interface{}) {
	fmt.Println("开始延迟运算")
	time.Sleep(time.Duration(count))
	//time.Sleep(3000000000)
	fun := reflect.ValueOf(function)
	var listVal []reflect.Value
	for _, v := range args {
		listVal = append(listVal, reflect.ValueOf(v))
	}
	fun.Call(listVal)
	fmt.Println("运行方法结束")
	//cc<-1
}

//每日定时运行初始化
func (this QuartzGo) init_2() {
	//var cc=make(chan int,1)
	//defer close(cc)
	//取当前时间前一天
	nowTime := time.Now()
	oneDayDir, err := time.ParseDuration("-24h")
	if err != nil {
		panic(err)
	}
	nowTime = nowTime.Add(oneDayDir)
	nowString := nowTime.Format(templeTime)
	//println(nowString)此时为前一天运行时
	nowString = nowString[:11] + this.tim
	//设置初始运行时间
	this.oldTime, err = time.ParseInLocation(templeTime, nowString, time.Local)
	if err != nil {
		panic(err)
	}
	go this.runPorc2()
	//_=<-cc
	//this.end=true
	fmt.Println("延迟运行方法结束")
}
func (this QuartzGo) close() {
	this.end = true
}
func (this QuartzGo) runPorc2() {
	for true {
		//，如果时间加上一天，小于现在就运行，并更新运行时间
		runTim := this.oldTime
		oneDayD, _ := time.ParseDuration("24h")
		runTim = runTim.Add(oneDayD)
		if runTim.Before(time.Now()) {
			fun := reflect.ValueOf(this.function)
			var listVal []reflect.Value
			for _, v := range this.args {
				listVal = append(listVal, reflect.ValueOf(v))
			}
			fun.Call(listVal)
			fmt.Println("运行方法结束")
			this.oldTime = this.oldTime.Add(oneDayD)
		}
		//if this.end==true {
		//	fmt.Println("end")
		//	break
		//}
	}
	fmt.Println("运行方法结束")
	//cc<-1
}

//获得当前日期开始时间
func DaytTimeBegin() (tim time.Time) {
	nowTime := time.Now()
	nowString := nowTime.Format(templeTime)
	//println(nowString)
	nowString = nowString[:10] + " 00:00:00"
	//tim,err:=time.ParseInLocation(templeTime,nowString,time.Local)
	//begin:=string(nowTime.Year())+"-"+nowTime.Month().String()+"-"+string(nowTime.Day())+" 00:00:00"
	//println(tim.Format(templeTime),err)
	return tim
}
func timeDuration() {
	//Add方法和Sub方法是相反的，获取t0和t1的时间距离d是使用Sub
	//将t0加d获取t1就是使用Add方法
	k := time.Now()
	//一天之前
	d, _ := time.ParseDuration("-24h")
	fmt.Println(k.Add(d))
	//一周之前
	fmt.Println(k.Add(d * 7))
	//一月之前
	fmt.Println(k.Add(d * 30))
}
func testMethod() {
	for i := 0; i < 10; i++ {
		fmt.Print(i)
	}
}
func main() {
	//t1:=time.Now()
	//var quartzGo QuartzGo;
	//var args []interface{};
	//quartzGo.Init(0,"30",testMethod,args)
	//elapsed := time.Since(t1)
	//fmt.Println("App elapsed: ", elapsed)
	var quartzGo QuartzGo
	var args []interface{}
	//quartzGo.Init(0,"5",testMethod,args)
	//quartzGo.Init(1,"2019-05-13 15:30:00",testMethod,args)
	quartzGo.Init(2, "15:34:00", testMethod, args)
	for true {
		tim, _ := time.ParseInLocation(templeTime, "2019-05-13 15:38:00", time.Local)
		if time.Now().After(tim) {
			break
		}
		//time.Sleep(3000)
	}

	quartzGo.close()
	fmt.Println("App elapsed: ", time.Now())
}
